package com.xy.blog.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.xy.blog.core.exception.BaseException;
import com.xy.blog.core.jwt.JWTUtils;
import com.xy.blog.core.service.IBaseService;
import com.xy.blog.core.springmvc.result.page.PageReq;
import com.xy.blog.core.springmvc.result.page.PageResp;
import com.xy.blog.core.utils.AESUtil;
import com.xy.blog.user.controller.model.req.query.AccountQuery;
import com.xy.blog.user.dao.impl.AccountDaoImpl;
import com.xy.blog.user.dao.impl.SysInfoDaoImpl;
import com.xy.blog.user.dao.impl.UserDaoImpl;
import com.xy.blog.user.dao.model.AccountDO;
import com.xy.blog.user.dao.model.SysInfoDO;
import com.xy.blog.user.dao.model.UserDO;
import com.xy.blog.user.exception.constants.AccountErrorCode;
import com.xy.blog.user.mapstruct.AccountConverter;
import com.xy.blog.user.service.IAccountService;
import com.xy.blog.user.service.model.AccountBO;
import com.xy.blog.user.service.model.LoginBO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zanhonglei
 * @version V1.0
 * @Description:
 * @date 2020/3/7
 */
@Service
public class AccountServiceImpl implements IBaseService<AccountQuery, AccountBO> , IAccountService {

    @Value("${aes.key}")
    private String aesKey;

    private static final Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);

    @Autowired
    private AccountDaoImpl accountDao;

    @Autowired
    private AccountConverter accountConverter;

    @Autowired
    private UserDaoImpl userDaoImpl;

    private static Long EXPIRE_OF_HOUR;

    private static String SECRET;

    @Autowired
    private SysInfoDaoImpl sysInfoDaoImpl;


    @PostConstruct
    private void init() {
        List<SysInfoDO> sysInfoDOS = sysInfoDaoImpl.selectAll();
        if (sysInfoDOS != null && sysInfoDOS.size() > 0) {
            SysInfoDO sysInfoDO = sysInfoDOS.get(0);
            SECRET = sysInfoDO.getSecret();
            EXPIRE_OF_HOUR = sysInfoDO.getTokenExpire();
        } else {
            logger.info("!!!!!!!!!!!秘钥和过期时间初始化失败!!!!!!!");
        }
    }

    @Override
    public PageResp<AccountBO> listByPage(PageReq<AccountQuery> req) throws BaseException {
        PageResp<AccountDO> accountDOPageResp = accountDao.listByPage(req);
        PageResp<AccountBO> resp = accountConverter.do2Bo(accountDOPageResp);
        List<AccountDO> list = accountDOPageResp.getList();
        List<AccountBO> data = new ArrayList<>(list.size());
        List<Long> userIds = new ArrayList<>();
        list.forEach(item->{
            userIds.add(item.getUserId());
        });
        List<UserDO> userDOS = userDaoImpl.listByIds(userIds);
        Map<Long, UserDO> userMaps = new HashMap<>();
        userDOS.forEach(item->{
            userMaps.put(item.getId(), item);
        });

        list.forEach(item->{
            AccountBO accountBO = accountConverter.do2Bo(item);
            UserDO userDO = userMaps.get(item.getUserId());
            accountBO.setUserId(userDO.getId());
            data.add(accountBO);
        });

        resp.setList(data);

        return resp;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void save(AccountBO item) throws BaseException {
        AccountDO query = new AccountDO();
        query.setAccount(item.getAccount());
        if (accountDao.selectCount(query) > 0) {
            throw new BaseException(AccountErrorCode.ACCOUNT_EXITS);
        }
        String decrypt = AESUtil.decrypt(item.getPassword(), aesKey);
        item.setPassword(BCrypt.hashpw(decrypt,item.getAccount()));
        AccountDO accountDO = accountConverter.bo2Do(item);
        accountDao.save(accountDO);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void update(AccountBO item) throws BaseException {
        AccountDO accountDO = accountConverter.bo2Do(item);
        accountDao.updateById(accountDO);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void deleteById(Long id) throws BaseException {
        accountDao.deleteById(id);
    }

    @Override
    public AccountBO getById(Long id) throws BaseException {
        return accountConverter.do2Bo(accountDao.getById(id));
    }

    @Override
    public LoginBO login(String account, String password) {
        LoginBO loginBO = new LoginBO();
        AccountDO accountDO = new AccountDO();
        accountDO.setAccount(account);
        AccountDO byAccount = accountDao.getByAccount(account);
        if (byAccount == null) {
            throw new BaseException(AccountErrorCode.ACCOUNT_NOT_EXITS);
        }
        String decrypt = AESUtil.decrypt(password, aesKey);
        Long userId = byAccount.getUserId();
        UserDO userInfo = userDaoImpl.getById(userId);
        loginBO.setUserName(userInfo.getUserName());
        loginBO.setExpire(EXPIRE_OF_HOUR);
        String subject = JSONObject.toJSONString(userInfo);
        if (BCrypt.checkpw(decrypt, byAccount.getPassword())) {
            loginBO.setToken(JWTUtils.createToken(SECRET, subject, EXPIRE_OF_HOUR));
            return loginBO;
        } else {
            throw new BaseException(AccountErrorCode.PASSWORD_INCORRECT);
        }
    }

    @Override
    public void logout(String token) {

    }

    @Override
    public boolean validateToken(String token) {
        return JWTUtils.validateToken(token,SECRET);
    }





}
